package vip.xiaomaoxiaoke.idempotent.support;

import com.google.common.base.Preconditions;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;

/**
 * 执行记录，与sql表保持一致，
 * 此实体在数据库中有两个唯一索引：一个是主键id
 * 另一个是type+uniqueKey组成的唯一索引
 */
@NoArgsConstructor
@Data
public class ExecutionRecord {


    private static final Integer STATUS_NONE = 0;
    private static final Integer STATUS_ING = 1;
    private static final Integer STATUS_DONE_SUCCESS = 2;
    private static final Integer STATUS_DONE_ERROR = 3;

    /**
     * 主键
     * */

    private Long id;

    /**
     * 业务组
     * */
    private Integer type;

    /**
     * 唯一标识
     * */
    private String uniqueKey;

    /**
     * 响应结果
     * */
    private String result;

    /**
     * 记录状态
     * */
    private Integer status;

    /**
     * 创建时间
     * */
    private Date createDate;

    /**
     * 更新时间
     * */
    private Date updateDate;

    /**
     * 判断是否在执行过程中
     * */
    public boolean isIng() {
        return STATUS_ING.equals(getStatus());
    }

    /**
     * 判断是否已完成
     * 成功失败都属于已完成
     * 在幂等性中，是不区分成功与失败的
     * */
    public boolean isDone() {
        return isSuccess() || isError();
    }

    /**
     * 是否执行成功
     * */
    public boolean isSuccess() {
        return STATUS_DONE_SUCCESS.equals(getStatus());
    }

    /**
     * 是否执行失败
     * */
    public boolean isError(){
        return STATUS_DONE_ERROR.equals(getStatus());
    }

    /**
     * 设置成功的结果
     * */
    public void success(String result) {
        setResult(result);
        setStatus(STATUS_DONE_SUCCESS);
        setUpdateDate(new Date());
    }

    /**
     * 设置失败的结果
     * */
    public void error(String error) {
        setResult(error);
        setStatus(STATUS_DONE_ERROR);
        setUpdateDate(new Date());
    }

    /**
     * 转化方法
     * */
    public static ExecutionRecord apply(Integer group, String key){
        // 数据校验
        Preconditions.checkArgument(group != null);
        Preconditions.checkArgument(StringUtils.isNoneBlank(key));

        // 数据封装
        ExecutionRecord executionRecord = new ExecutionRecord();
        executionRecord.setType(group);
        executionRecord.setUniqueKey(key);
        return executionRecord;
    }

    // 设置初始化方法
    public void init() {
        setStatus(STATUS_NONE);
        setCreateDate(new Date());
    }

    /**
     * 设置状态在执行中
     * */
    public void ing() {
        setStatus(STATUS_ING);
    }

    /**
     * 无状态，也可以理解为对象刚刚创建完成
     * */
    public boolean isNone() {
        return STATUS_NONE.equals(getStatus());
    }
}
